home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / pgp20src.zip / CONFIG.C < prev    next >
C/C++ Source or Header  |  1992-08-21  |  11KB  |  465 lines

  1. /*    config.c  - config file parser by Peter Gutmann
  2.     Parses config file for PGP
  3.  
  4.     Modified 24 Jun 92 - HAJK
  5.     Misc fixes for VAX C restrictions.
  6.  
  7. */
  8.  
  9. #include <ctype.h>
  10. #include <string.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include "usuals.h"
  14. #include "pgp.h"
  15. /* The external config variables we can set here are referenced in pgp.h */
  16.  
  17. /* Return values */
  18.  
  19. #define ERROR    -1
  20. #define OK        0
  21.  
  22. /* The types of error we check for */
  23.  
  24. enum { NO_ERROR, ILLEGAL_CHAR_ERROR, LINELENGTH_ERROR };
  25.  
  26. #define CPM_EOF            0x1A    /* ^Z = CPM EOF char */
  27.  
  28. #define MAX_ERRORS        3        /* Max.no.errors before we give up */
  29.  
  30. #define LINEBUF_SIZE    100        /* Size of input buffer */
  31.  
  32. int line;                        /* The line on which an error occurred */
  33. int errCount;                    /* Total error count */
  34. boolean hasError;                /* Whether this line has an error in it */
  35.  
  36. /* The settings parsed out by getAssignment() */
  37.  
  38. char str[ LINEBUF_SIZE ];
  39. int value;
  40. boolean flag;
  41.  
  42. /* A .CFG file roughly follows the format used in the world-famous HPACK
  43.    archiver and is as follows:
  44.  
  45.     - Leading spaces/tabs (whitespace) are ignored.
  46.  
  47.     - Lines with a '#' as the first non-whitespace character are treated as
  48.       comment lines.
  49.  
  50.     - All other lines are treated as config options for the program.
  51.  
  52.     - Lines may be terminated by either linefeeds, carriage returns, or
  53.       carriage return/linefeed pairs (the latter being the DOS default method
  54.       of storing text files).
  55.  
  56.     - Config options have the form:
  57.  
  58.       <option> '=' <setting>
  59.  
  60.       where <setting> may be 'on', 'off', a numeric value, or a string
  61.       value.
  62.  
  63.     - If strings have spaces or the '#' character inside them they must be
  64.       surrounded by quote marks '"' */
  65.  
  66. /* The types of input we can expect */
  67.  
  68. typedef enum { BOOL, NUMERIC, STRING } INPUT_TYPE;
  69.  
  70. /* Intrinsic variables */
  71.  
  72. #define NO_INTRINSICS        17
  73.  
  74. enum
  75. {    ARMOR, COMPRESS, SHOWPASS, KEEPBINARY, LANGUAGE,
  76.     MYNAME, TEXTMODE, TMP, TZFIX, VERBOSE, BAKRING,
  77.     ARMORLINES, COMPLETES_NEEDED, MARGINALS_NEEDED, PAGER,
  78.     CERT_DEPTH, CHARSET
  79. };
  80.  
  81. char *intrinsics[] =
  82. {    "ARMOR", "COMPRESS", "SHOWPASS", "KEEPBINARY", "LANGUAGE",
  83.     "MYNAME", "TEXTMODE", "TMP", "TZFIX", "VERBOSE", "BAKRING",
  84.     "ARMORLINES", "COMPLETES_NEEDED", "MARGINALS_NEEDED", "PAGER",
  85.     "CERT_DEPTH", "CHARSET"
  86. };
  87.  
  88. INPUT_TYPE intrinsicType[] =
  89. {    BOOL, BOOL, BOOL, BOOL, STRING,
  90.     STRING, BOOL, STRING, NUMERIC, BOOL, STRING,
  91.     NUMERIC, NUMERIC, NUMERIC, STRING,
  92.     NUMERIC, STRING
  93. };
  94.  
  95. /* Possible settings for variables */
  96.  
  97. #define NO_SETTINGS            2
  98.  
  99. char *settings[] = { "OFF", "ON" };
  100.  
  101.  
  102. /* Search a list of keywords for a match */
  103.  
  104. int lookup( char *key, int keyLength, char *keyWords[], int range )
  105.     {
  106.     int index;
  107.  
  108.     /* Make the search case insensitive */
  109.     for( index = 0; index < keyLength; index++ )
  110.         key[ index ] = toupper( key[ index ] );
  111.  
  112.     for( index = 0; index < range; index++ )
  113.         if( !strncmp( key, keyWords[ index ], keyLength ) )
  114.             return( index );
  115.  
  116.     /* Key not found */
  117.     return( ERROR );
  118.     }
  119.  
  120. /* Extract a token from a buffer */
  121. int extractToken( char *buffer, int *endIndex, int *length )
  122. {
  123.     int index = 0, tokenStart;
  124.     char ch;
  125.  
  126.     /* Skip whitespace */
  127.     for( ch = buffer[ index ]; ch && ( ch == ' ' || ch == '\t' ); ch = buffer[ index ] )
  128.         index++;
  129.     tokenStart = index;
  130.  
  131.     /* Find end of setting */
  132.     while( index < LINEBUF_SIZE && ( ch = buffer[ index ] ) != '\0' && ch != ' ' && ch != '\t' )
  133.         index++;
  134.     *endIndex += index;
  135.     *length = index - tokenStart;
  136.  
  137.     /* Return start position of token in buffer */
  138.     return( tokenStart );
  139. }
  140.  
  141.  
  142. /* Get a string constant */
  143. int getaString( char *buffer, int *endIndex )
  144.     {
  145.     boolean noQuote = FALSE;
  146.     int stringIndex = 0, bufIndex = 1;
  147.     char ch = *buffer;
  148.  
  149.     /* Skip whitespace */
  150.     while( ch && ( ch == ' ' || ch == '\t' ) )
  151.         ch = buffer[ bufIndex++ ];
  152.  
  153.     /* Check for non-string */
  154.     if( ch != '\"' )
  155.         {
  156.         *endIndex += bufIndex;
  157.  
  158.         /* Check for special case of null string */
  159.         if( !ch )
  160.             {
  161.             *str = '\0';
  162.             return( OK );
  163.             }
  164.  
  165.         /* Use nasty non-rigorous string format */
  166.         noQuote = TRUE;
  167.         }
  168.  
  169.     /* Get first char of string */
  170.     if( !noQuote )
  171.         ch = buffer[ bufIndex++ ];
  172.  
  173.     /* Get string into string */
  174.     while( ch && ch != '\"' )
  175.         {
  176.         /* Exit on '#' if using non-rigorous format */
  177.         if( noQuote && ch == '#' )
  178.             break;
  179.  
  180.         str[ stringIndex++ ] = ch;
  181.         ch = buffer[ bufIndex++ ];
  182.         }
  183.  
  184.     /* If using the non-rigorous format, stomp trailing spaces */
  185.     if( noQuote )
  186.         while( stringIndex > 0 && str[ stringIndex - 1 ] == ' ' )
  187.             stringIndex--;
  188.  
  189.     str[ stringIndex++ ] = '\0';
  190.     *endIndex += bufIndex;
  191.  
  192.     /* Check for missing string terminator */
  193.     if( ch != '\"' && !noQuote )
  194.         {
  195.         printf( "Unterminated string in line %d\n", line );
  196.         hasError = TRUE;
  197.         errCount++;
  198.         return( ERROR );
  199.         }
  200.  
  201.     return( OK );
  202.     }
  203.  
  204. /* Get an assignment to an intrinsic */
  205. int getAssignment( char *buffer, int *endIndex, INPUT_TYPE settingType )
  206. {
  207.     int settingIndex = 0, length;
  208.  
  209.     buffer += extractToken( buffer, endIndex, &length );
  210.  
  211.     /* Check for an assignment operator */
  212.     if ( *buffer != '=' )
  213.     {
  214.         printf( "Expected '=' in line %d\n", line );
  215.         hasError = TRUE;
  216.         errCount++;
  217.         return( ERROR );
  218.     }
  219.     buffer++;        /* Skip '=' */
  220.  
  221.     buffer += extractToken( buffer, endIndex, &length );
  222.  
  223.     switch( settingType )
  224.     {
  225.         case BOOL:
  226.             /* Check for known intrinsic - really more general than just
  227.                checking for TRUE or FALSE */
  228.             if( ( settingIndex = lookup( buffer, length, settings, NO_SETTINGS ) ) == ERROR )
  229.             {
  230.                 printf( "Unknown setting '%s' in line %d\n", buffer, line );
  231.                 hasError = TRUE;
  232.                 errCount++;
  233.                 return( ERROR );
  234.             }
  235.  
  236.             flag = ( settingIndex == 0 ) ? FALSE : TRUE;
  237.             break;
  238.  
  239.         case STRING:
  240.             /* Get a string */
  241.             getaString( buffer, &length );
  242.             break;
  243.  
  244.         case NUMERIC:
  245.             /* Get numeric input.  Error checking is a pain since atoi()
  246.                 has no real equivalent of NAN */
  247.             value = atoi( buffer );
  248.             break;
  249.     }
  250.  
  251.     return( settingIndex );
  252. }
  253.  
  254.  
  255. /* Process a config file */
  256. int processConfigFile( char *configFileName )
  257. {
  258.     FILE *configFilePtr;
  259.     int ch = 0, theCh;
  260.     int errType, errPos = 0, lineBufCount, intrinsicIndex;
  261.     int index;
  262.     char inBuffer[ LINEBUF_SIZE ];
  263.  
  264.     line = 1;
  265.     errCount = 0;
  266.  
  267.     if( ( configFilePtr = fopen( configFileName, "r" ) ) == NULL )
  268.     {
  269.         printf( "Cannot open configuration file %s\n", configFileName );
  270.         return( OK );    /* treat like empty config file */
  271.     }
  272.  
  273.     /* Process each line in the configFile */
  274.     while( ch != EOF )
  275.     {
  276.         /* Skip whitespace */
  277.         while( ( ( ch = getc( configFilePtr ) ) == ' ' || ch == '\t' ) && ch != EOF );
  278.  
  279.         /* Get a line into the inBuffer */
  280.         hasError = FALSE;
  281.         lineBufCount = 0;
  282.         errType = NO_ERROR;
  283.         while( ch != '\r' && ch != '\n' && ch != CPM_EOF && ch != EOF )
  284.         {
  285.             /* Check for an illegal char in the data */
  286.             if( ( ch < ' ' || ch > '~' ) && ch != '\r' && ch != '\n' &&
  287.                 ch != ' ' && ch != '\t' && ch != CPM_EOF && ch != EOF )
  288.             {
  289.                 if( errType == NO_ERROR )
  290.                     /* Save position of first illegal char */
  291.                     errPos = lineBufCount;
  292.                 errType = ILLEGAL_CHAR_ERROR;
  293.             }
  294.  
  295.             /* Make sure the path is of the correct length.  Note that the
  296.                code is ordered so that a LINELENGTH_ERROR takes precedence over
  297.                an ILLEGAL_CHAR_ERROR */
  298.             if( lineBufCount > LINEBUF_SIZE )
  299.                 errType = LINELENGTH_ERROR;
  300.             else
  301.                 inBuffer[ lineBufCount++ ] = ch;
  302.  
  303.             if( ( ch = getc( configFilePtr ) ) == '#' )
  304.             {
  305.                 /* Skip comment section and trailing whitespace */
  306.                 while( ch != '\r' && ch != '\n' && ch != CPM_EOF && ch != EOF )
  307.                     ch = getc( configFilePtr );
  308.                 break;
  309.             }
  310.         }
  311.  
  312.         /* Skip trailing whitespace and add der terminador */
  313.         while( ( theCh = inBuffer[ lineBufCount - 1 ] ) == ' ' || theCh == '\t' )
  314.             lineBufCount--;
  315.         inBuffer[ lineBufCount ] = '\0';
  316.  
  317.         /* Process the line unless its a blank or comment line */
  318.         if( lineBufCount && *inBuffer != '#' )
  319.         {
  320.             switch( errType )
  321.             {
  322.                 case LINELENGTH_ERROR:
  323.                     inBuffer[ 80 - strlen( "Line '%s...' too long\n" ) - 3 ] = '\0';
  324.                                 /* Truncate to fit screen size (3 = '%s' + 1) */
  325.                     printf( "Line '%s...' too long\n", inBuffer );
  326.                     errCount++;
  327.                     break;
  328.  
  329.                 case ILLEGAL_CHAR_ERROR:
  330.                     printf( "> %s\n  ", inBuffer );
  331.                     while( errPos-- )
  332.                         putchar( ' ' );
  333.                     printf( "^ Bad character in command on line %d\n", line );
  334.                     errCount++;
  335.                     break;
  336.  
  337.                 default:
  338.                     for( index = 0;
  339.                          index < LINEBUF_SIZE && ( ch = inBuffer[ index ] ) != '\0' && ch != ' ' && ch != '\t';
  340.                          index++ );
  341.                     if( ( intrinsicIndex = lookup( inBuffer, index, intrinsics, NO_INTRINSICS ) ) == ERROR )
  342.                     {
  343.                         printf( "Unknown command '%s' in line %d\n", inBuffer, line );
  344.                         errCount++;
  345.                     }
  346.                     else
  347.                     {
  348.                         /* Get the value to set to, either as a string, a
  349.                            numeric value, or a boolean flag */
  350.                         getAssignment( inBuffer + index, &index, intrinsicType[ intrinsicIndex ] );
  351.  
  352.                         if( !hasError )
  353.                             switch( intrinsicIndex )
  354.                             {
  355.                                 case ARMOR:
  356.                                     emit_radix_64 = flag;
  357.                                     break;
  358.  
  359.                                 case COMPRESS:
  360.                                     compress_enabled = flag;
  361.                                     break;
  362.  
  363.                                 case SHOWPASS:
  364.                                     showpass = flag;
  365.                                     break;
  366.  
  367.                                 case KEEPBINARY:
  368.                                     keepctx = flag;
  369.                                     break;
  370.  
  371.                                 case LANGUAGE:
  372.                                     strncpy(language, str, 15);
  373.                                     break;
  374.  
  375.                                 case BAKRING:
  376.                                     strcpy(floppyring, str);
  377.                                     break;
  378.  
  379.                                 case MYNAME:
  380.                                     strcpy(my_name, str);
  381.                                     break;
  382.  
  383.                                 case TEXTMODE:
  384.                                     if( flag )
  385.                                         lit_mode = MODE_TEXT;
  386.                                     break;
  387.  
  388.                                 case TMP:
  389.                                     /* directory pathname to store temp files */
  390.                                     strcpy(tmpdir, str);
  391.                                     break;
  392.  
  393.                                 case TZFIX:
  394.                                     /* How many hours to add to time() to get GMT. */
  395.                                     /* Compute seconds from hours to shift to GMT: */
  396.                                     timeshift = 3600L * (long) value;
  397.                                     break;
  398.  
  399.                                 case VERBOSE:
  400.                                     verbose = flag;
  401.                                     break;
  402.                                 
  403.                                 case ARMORLINES:
  404.                                     pem_lines = value;
  405.                                     break;
  406.  
  407.                                 case MARGINALS_NEEDED:
  408.                                     marg_min = value;
  409.                                     if (marg_min < 1) 
  410.                                         marg_min = 1;
  411.                                     break;
  412.  
  413.                                 case COMPLETES_NEEDED:
  414.                                     compl_min = value;
  415.                                     if (compl_min < 1) 
  416.                                         compl_min = 1;
  417.                                     if (compl_min > 4) 
  418.                                         compl_min = 4;
  419.                                     break;
  420.  
  421.                                 case CERT_DEPTH:
  422.                                     max_cert_depth = value;
  423.                                     if (max_cert_depth < 0) 
  424.                                         max_cert_depth = 0;
  425.                                     if (max_cert_depth > 8) 
  426.                                         max_cert_depth = 8;
  427.                                     break;
  428.  
  429.                                 case PAGER:
  430.                                     strcpy(pager, str);
  431.                                     break;
  432.                                 
  433.                                 case CHARSET:
  434.                                     strcpy(charset, str);
  435.                                     break;
  436.  
  437.                             }
  438.                     }
  439.             }
  440.         }
  441.  
  442.         /* Handle special-case of ^Z if configFile came off an MSDOS system */
  443.         if( ch == CPM_EOF )
  444.             ch = EOF;
  445.  
  446.         /* Exit if there are too many errors */
  447.         if( errCount >= MAX_ERRORS )
  448.             break;
  449.  
  450.         line++;
  451.     }
  452.  
  453.     fclose( configFilePtr );
  454.  
  455.     /* Exit if there were errors */
  456.     if( errCount )
  457.     {
  458.         printf( "%s%d errors detected\n", ( errCount >= MAX_ERRORS ) ?
  459.                 "Maximum level of " : "", errCount );
  460.         return( ERROR );
  461.     }
  462.  
  463.     return( OK );
  464. }
  465.